不知不覺就進展到第七天了,今天的目標是透過官方文件來理解React最基本的概念。
官方文件把這裡的東西拆成兩篇文章來講,但我覺得要一次讀完比較容易理解。
基本上官方文件寫得很詳細,我覺得關於element就總括一句話:
官方文件寫到:
Unlike browser DOM elements, React elements are plain objects, and are cheap to create. React DOM takes care of updating the DOM to match the React elements.
這裡的重點就一句話:React 的 element是一個純的Object。
【小補充】
這裡我想講一下,關於element 是指在畫面上看到的html 標籤,例如:div、p
那這些element並不是一個"純"object嗎?
還真的不是,每個element的object會有不同的屬性及方法,基本的屬性有:children、childrenNodes...之類的,所有html元素都有繼承來自 element Object 的屬性及方法。
詳細可以參考w3school的說明
至於Dom,DOM 的全文是document object model,中文是文件物件模型。
使用dom能夠操作html的元素(每個tag),如果JavaScript沒有DOM模型,則與其他程式語言並無不同。
透過dom模型操作html的元素(或變更元素中的屬性),都能夠使網頁與使用者的互動增加。
官方在element的地方有標註一個小說明:
大家可能會將element與Component搞混,但兩者並不相同,Component 是由 element 所「組成」的。
如果我們要在畫面上顯示element,會將需要顯示的元素render到dom之中,這裡直接拿官方的範例:
const root = ReactDOM.createRoot(
document.getElementById('root')
);
const element = <h1>Hello, world</h1>;
root.render(element);
React Element是不可改變的,當我們創造了一個element,並不能夠再去改變他的屬性,因為這個React element代表某個時間點的畫面
官方在文件中也有提供如何更新element的資料,這裡來解讀一下:
const root = ReactDOM.createRoot(
document.getElementById('root')
);
function tick() {
const element = (
<div>
<h1>Hello, world!</h1>
<h2>It is {new Date().toLocaleTimeString()}.</h2>
</div>
);
root.render(element);
}
setInterval(tick, 1000);
首先,root 就是一個ReactDom
接著有一個tick的function,在function 之中寫好element,並將element reder回Dom之中,最後每一秒鐘(1000毫秒)跑一次tuck function
const 在JS之中代表常數,常數指的是不可重複宣告、不可重複給值的
那為什麼用呼叫的方式就沒有報錯呢?
這主要原因是因為 "const" 本身是有function scope的,因此每次宣告的生命週期只在當下的那個function之中
所以在react官方範例之中,透過scope的特性來更新element的內容,最後每次更新都render到DOM之中來達到我們要更新element的目的。
React DOM 會將 element 和它的 children 與先前的狀態做比較,並且只更新必要的 DOM 達到理想的狀態。
(ps.這句話是來自於官方文件,我覺得沒有什麼好解釋的就複製貼上XD
在官方文件中,元件(Components)跟屬性(Props)是在同一個章節介紹,因此我這裡也一倂介紹。
一開始官方給Components的定義是:
概念上來說,component 就像是 JavaScript 的 function,它接收任意的參數(稱之為「props」)並且回傳描述畫面的 React element。
簡單來說,Component就是"類"function的概念,接收的參數不叫parameter叫做props,這個類function 會回傳element。
官方的範例給出兩種宣告元件的方式:
function Welcome(props) {
return <h1>Hello, {props.name}</h1>;
}
class Welcome extends React.Component {
render() {
return <h1>Hello, {this.props.name}</h1>;
}
}
這兩種方式都是可行的。
ps.關於js的class,我在Day4的時候有做過小補充,忘記的小夥伴可以回去看看,順邊幫我按個讚。官方文件在這裡有埋下一個伏筆:Function 和 Class component 兩者都擁有額外的特性
官方的範例看起來沒甚麼難度,我們把柬埔寨專案拿出來加一些東西XD
因為我懶得排版了,我直接在left的地方加個comment資料
我們直接在left.js之中修改
import React from "react";
const Left = () => {
let slogan = ["月薪3000美金,包吃包住","工作輕鬆 - 辨公室客服","每三個月一張返鄉機票","成就自我價值"];
let comments = [
{ name: "王大嗨" , age: "28" , comment: "我沒想到我可以這麼年輕就挑戰副理職位,年薪上看兩百萬" },
{ name: "江超人" , age: "26" , comment: "謝謝你,柬埔人,我的超人" },
{ name: "連載中" , age: "32" , comment: "謝謝公司願意給我這個機會來挑戰自己" },
{ name: "王曉華" , age: "42" , comment: "沒想到二度就業婦女都會有這麼好的就業機會" }
];
return (
<div>
<ol>
{
slogan.map( value => {
return <li key={value.toString()}>{value}</li>;
})
}
</ol>
<hr style={{width:"90%"}}/>
{
comments.map( value => {
return <Comment name={value.name} age={value.age} comment={value.comment} key={value.toString()}/>
})
}
</div>
);
}
function Comment({name , age , comment}){
return <div style={{width:"100%"}}>
<p style={{width:"100%" , marginLeft:"3rem"}}>姓名:{name} 年齡:{age}</p>
<p style={{width:"100%" , marginLeft:"3rem"}}>工作感想:{comment}</p>
<hr style={{width:"90%"}}/>
</div>;
}
export default Left;
一開始我們創建了一個 名稱叫做 comment的array,array中4個object
接下來我們寫一個function ,命名就是component的名稱,接著我們設定這個function要接收三個props
(這裡我跟官方範例的做法比較不一樣,稍後會解釋),最後在原本的return 之中加入呼叫component的語法:<ComponentName />
並將需要帶進去的參數逐一填寫,即可。
如果採用官方範例,那我們剛剛建立comment component要改成如下:
function Comment(props){
return <p>{props.name}</p>;
}
這兩個做法差在哪裡?
主要是 在React之中預設 Component接收到的參數 是"一個props"
當我們在呼叫 Component時,會帶入多個參數。
這個時候Components 的props是一個object
因此如果在接收的地方只有寫props,那麼要取的參數就要寫成props.xxx
那我們把props改成一個大括號加入properties的名稱,這時候其實React 幫我們偷偷執行了這個過程:
let {name , age , comment } = props;
這個東西叫做解構(Destruct)
如果我們從物件中拿資料時,一個一個得從物件拿出來,整體非常耗時且程式碼可能會變得很龐大
因此destruct這個技巧可以幫助我們大幅度縮縮短取資料的過程。
只要物件的屬性名稱跟變數一樣,就可以利用destruct的方式將資料取出
例如:
明天我們要繼續來看 React的 Status
(React好像太多了,有點寫不完XD)